package com.sheepone.distributor.autoconfigure;

import com.sheepone.distributor.Distributor;
import com.sheepone.distributor.WorkerStation;
import com.sheepone.distributor.WorkerStationManager;
import com.sheepone.distributor.anno.StationEventTopicListener;
import com.sheepone.distributor.config.DistributorCreator;
import com.sheepone.distributor.exeception.AbsentWorkerStation;
import com.sheepone.distributor.exeception.MultipleListenersForTopic;
import com.sheepone.distributor.listener.StationEventListener;
import com.sheepone.util.CglibUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.Map;
import java.util.Objects;

/**
 * @author Miss.杨
 * @description
 * @since 2023-12-07 21:56
 */
@Configuration
@EnableConfigurationProperties({WorkerStationBootConfig.class, DistributorLineBootConfig.class})
public class DistributorAutoConfigure implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        Map<String, Object> eventListenerMap = applicationContext.getBeansWithAnnotation(StationEventTopicListener.class);
        WorkerStationManager workerLineManager = WorkerStationManager.INSTANCE;
        for (Object eventListener : eventListenerMap.values()) {
            // 这里需要过滤一下代理类，比如用了Sentinel啥的，可能就会对bean做增强，
            // 然后getClass获取到的是一个代理类，代理类上是拿不到Channel注解的
            if (eventListener instanceof StationEventListener) {
                Class<?> realClazz = CglibUtil.filterCglibProxyClass(eventListener.getClass());
                StationEventTopicListener listener = realClazz.getAnnotation(StationEventTopicListener.class);
                String station = listener.station();
                if (!station.isEmpty()) {
                    WorkerStation workerStation = workerLineManager.getWorkerStation(station);
                    if (workerStation == null) {
                        throw new AbsentWorkerStation(station);
                    }
                    String topic = listener.topic();
                    if (Objects.equals(topic, "")) {
                        throw new IllegalArgumentException("topic can not be empty");
                    }
                    if (!workerStation.register(topic, (StationEventListener) eventListener)) {
                        throw new MultipleListenersForTopic(station, topic);
                    }
                }
            }
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public Distributor distributor(DistributorLineBootConfig distributorLineConfig, WorkerStationBootConfig workerLineConfig) {
        WorkerStationManager.INSTANCE
                .registerWorkerStation(workerLineConfig.getWorkerStations());

        return DistributorCreator.create(distributorLineConfig).start();
    }
}
